const { Service } = require("egg");
const { Builder } = require("selenium-webdriver");
const chrome = require("selenium-webdriver/chrome");

class SeleniumPoolService extends Service {
  constructor(ctx) {
    super(ctx);

    // 初始化全局变量（如果不存在）
    this.initGlobalVars();
  }

  /**
   * 初始化全局变量，存储窗口池核心状态
   */
  initGlobalVars() {
    if (!this.app.seleniumGlobal) {
      this.app.seleniumGlobal = {
        pool: [], // 窗口池数组
        initialized: false, // 是否已初始化
        timeoutChecker: null, // 超时检查定时器
        config: {
          windowCount: 5,
          idleTimeout: 3 * 60 * 1000, // 3分钟超时
        },
      };
    }
  }

  /**
   * 获取全局状态对象
   */
  get global() {
    return this.app.seleniumGlobal;
  }

  /**
   * 初始化窗口池（先关闭所有原有窗口）
   */
  async init() {
    // 检查是否已初始化
    if (this.global.initialized) {
      this.ctx.logger.info("Selenium窗口池已初始化，无需重复操作");
      return;
    }

    // 清理可能存在的残留窗口
    await this.cleanupExistingWindows();

    // 从配置中获取窗口数量
    const { seleniumPool } = this.app.config;
    if (seleniumPool) {
      this.global.config = { ...this.global.config, ...seleniumPool };
    }

    // 创建指定数量的新窗口
    await this.createWindows(this.global.config.windowCount);

    // 启动定时检查超时任务
    this.startTimeoutChecker();

    this.global.initialized = true;
    this.ctx.logger.info(
      `Selenium窗口池初始化完成，共创建${this.global.config.windowCount}个窗口`
    );
  }

  /**
   * 批量创建窗口
   * @param {number} count - 要创建的窗口数量
   */
  async createWindows(count) {
    for (let i = 0; i < count; i++) {
      await this.createAndAddWindow();
    }
  }

  /**
   * 创建一个新窗口并添加到池
   */
  async createAndAddWindow() {
    let driver = await this.createDriver();
    let cdpPort = driver.cdpPort;
    driver = driver.driver;
    const newWindowId = `window-${Date.now()}-${Math.floor(
      Math.random() * 1000
    )}`;

    this.global.pool.push({
      id: newWindowId,
      driver,
      status: "idle",
      userId: null,
      lastActivity: Date.now(),
      cdpPort,
    });

    this.ctx.logger.info(`已创建新窗口: ${newWindowId}`);
    return newWindowId;
  }

  /**
   * 清理所有已存在的窗口
   */
  async cleanupExistingWindows() {
    if (this.global.pool.length > 0) {
      this.ctx.logger.info(`清理${this.global.pool.length}个原有窗口`);
      for (const window of this.global.pool) {
        try {
          await window.driver.quit();
          this.ctx.logger.info(`已关闭原有窗口${window.id}`);
        } catch (error) {
          this.ctx.logger.error(`关闭原有窗口${window.id}时出错:`, error);
        }
      }
      // 清空池
      this.global.pool = [];
    }
  }

  /**
   * 创建新的浏览器驱动实例
   */
  async createDriver() {
    let deviceList = [
      "iPhone 12 Pro",
      // "iPhone 14 Pro Max",
      // "iPhone XR",
      // "Samsung Galaxy S20 Ultra",
    ];
    let device = deviceList[Math.floor(Math.random() * deviceList.length)];
    const options = new chrome.Options();
    options.addArguments("--no-sandbox");
    options.addArguments("--disable-dev-shm-usage");
    options.addArguments("--window-size=430,932");
    // 禁用自动化控制特征
    options.addArguments("--disable-blink-features=AutomationControlled");
    // 排除自动化开关
    options.excludeSwitches("enable-automation");
    // options.addArguments(`user-agent=${ua}`);
    // 设置移动设备参数 - 这里以iPhone 13为例
    // options.setMobileEmulation({
    //   deviceName: device,
    // });
    if (this.config.env === "prod") {
      options.addArguments("--headless=new");
    }
    let cdpPort = 9222 + Math.floor(Math.random() * 100);
    options.addArguments(`--remote-debugging-port=${cdpPort}`);
    // 可根据需要添加其他配置
    // options.addArguments('--headless=new');
    let service = new chrome.ServiceBuilder(this.config.chromeDriver);
    let driver = new Builder()
      .forBrowser("chrome")
      .setChromeService(service)
      .setChromeOptions(options)
      .build();
    return {
      driver,
      cdpPort,
    };
  }

  /**
   * 为用户获取窗口（同一用户会获取相同窗口）
   * @param {string} userId - 用户唯一标识
   */
  async acquire(userId) {
    if (!this.global.initialized) {
      await this.init();
    }

    // 检查用户是否已有关联窗口
    const userWindow = this.global.pool.find(
      (item) => item.userId === userId && item.status === "busy"
    );
    if (userWindow) {
      // 更新活动时间
      userWindow.lastActivity = Date.now();
      this.ctx.logger.info(`用户${userId}继续使用窗口${userWindow.id}`);
      return userWindow;
    }

    // 为用户分配新的闲置窗口
    const idleWindow = this.global.pool.find((item) => item.status === "idle");
    if (!idleWindow) {
      this.ctx.logger.warn(`用户${userId}无法获取窗口，无闲置窗口`);
      return null;
    }

    // 标记窗口状态并关联用户
    idleWindow.status = "busy";
    idleWindow.userId = userId;
    idleWindow.lastActivity = Date.now();

    this.ctx.logger.info(`用户${userId}获取新窗口${idleWindow.id}`);
    return idleWindow;
  }

  /**
   * 释放用户的窗口（关闭并创建新窗口替代）
   * @param {string} userId - 用户唯一标识
   */
  async releaseByUser(userId) {
    const windowIndex = this.global.pool.findIndex(
      (item) => item.userId === userId
    );

    if (windowIndex === -1) {
      return false;
    }

    // 获取要关闭的窗口
    const windowToClose = this.global.pool[windowIndex];
    const windowId = windowToClose.id;

    try {
      // 关闭窗口
      await windowToClose.driver.quit();
      this.ctx.logger.info(`用户${userId}释放并关闭窗口${windowId}`);

      // 从池中移除
      this.global.pool.splice(windowIndex, 1);

      // 创建新窗口替代
      await this.createAndAddWindow();

      return true;
    } catch (error) {
      this.ctx.logger.error(`关闭窗口${windowId}时出错:`, error);
      try {
        this.global.pool.splice(windowIndex, 1);
        // 创建新窗口替代
        await this.createAndAddWindow();
      } catch (error) {}
      return false;
    }
  }

  /**
   * 彻底释放窗口（清除用户关联，关闭并创建新窗口）
   * @param {string} windowId - 窗口ID
   */
  async forceRelease(windowId) {
    const windowIndex = this.global.pool.findIndex(
      (item) => item.id === windowId
    );

    if (windowIndex === -1) {
      return false;
    }

    // 获取要关闭的窗口
    const windowToClose = this.global.pool[windowIndex];

    try {
      // 关闭窗口
      await windowToClose.driver.quit();
      this.ctx.logger.info(`窗口${windowId}被强制释放并关闭`);

      // 从池中移除
      this.global.pool.splice(windowIndex, 1);

      // 创建新窗口替代
      await this.createAndAddWindow();

      return true;
    } catch (error) {
      this.ctx.logger.error(`关闭窗口${windowId}时出错:`, error);
      return false;
    }
  }

  /**
   * 更新用户窗口的活动时间
   * @param {string} userId - 用户唯一标识
   */
  updateUserActivity(userId) {
    const window = this.global.pool.find((item) => item.userId === userId);
    if (window) {
      window.lastActivity = Date.now();
      return true;
    }
    return false;
  }

  /**
   * 获取用户的窗口
   * @param {string} userId - 用户唯一标识
   */
  getUserWindow(userId) {
    const window = this.global.pool.find((item) => item.userId === userId);
    if (window) {
      // 更新活动时间
      window.lastActivity = Date.now();
      return window;
    }
    return null;
  }

  /**
   * 启动定时检查超时任务
   */
  startTimeoutChecker() {
    // 如果已有定时器，先清除
    if (this.global.timeoutChecker) {
      clearInterval(this.global.timeoutChecker);
    }

    // 每分钟检查一次
    this.global.timeoutChecker = setInterval(async () => {
      const now = Date.now();
      const windowsToReplace = [];

      // 找出超时的窗口
      this.global.pool.forEach((window) => {
        if (
          window.status === "busy" &&
          now - window.lastActivity > this.global.config.idleTimeout
        ) {
          windowsToReplace.push(window.id);
        }
      });

      // 处理超时窗口：关闭并替换
      for (const windowId of windowsToReplace) {
        this.ctx.logger.warn(`窗口${windowId}因超时将被关闭并替换`);
        await this.forceRelease(windowId);
      }
    }, 60 * 1000);
  }

  /**
   * 获取当前窗口池状态
   */
  getPoolStatus() {
    return this.global.pool.map((item) => ({
      id: item.id,
      status: item.status,
      userId: item.userId,
      lastActivity: item.lastActivity,
    }));
  }

  /**
   * 关闭所有窗口并重置状态
   */
  async closeAll() {
    await this.cleanupExistingWindows();

    // 清除定时器
    if (this.global.timeoutChecker) {
      clearInterval(this.global.timeoutChecker);
      this.global.timeoutChecker = null;
    }

    this.global.initialized = false;
    this.ctx.logger.info("所有Selenium窗口已关闭并重置状态");
  }
}

module.exports = SeleniumPoolService;
